package com.party.mobile.biz.wechat;

import com.alibaba.fastjson.JSONObject;
import com.google.common.base.Charsets;
import com.party.api.dto.wechatPlatform.response.Oauth2AccessTokenResponse;
import com.party.api.service.wechatPlatform.IWechatPlatformService;
import com.party.common.constant.Constant;
import com.party.common.constant.WechatConstant;
import com.party.common.redis.StringJedis;
import com.party.common.utils.StringUtils;
import com.party.common.utils.wechat.WechatUtils;
import com.party.core.model.YesNoStatus;
import com.party.core.model.member.MemberExternalApp;
import com.party.core.model.member.MemberGroup;
import com.party.core.model.member.MemberMerchant;
import com.party.core.model.wechatPlatform.WechatOpenMember;
import com.party.core.model.wechatPlatform.WechatOpenPlatform;
import com.party.core.service.member.IMemberExternalAppService;
import com.party.core.service.member.IMemberMerchantService;
import com.party.core.service.wechat.IWechatAccountService;
import com.party.core.service.wechat.IWechatMerchantsService;
import com.party.core.service.wechat.IWechatSubscribeService;
import com.party.core.service.wechatPlatform.IWechatMerchantService;
import com.party.core.service.wechatPlatform.IWechatOpenMemberService;
import com.party.core.service.wechatPlatform.IWechatOpenPlatformService;
import com.party.mobile.web.dto.wechat.input.*;
import com.party.mobile.web.dto.wechat.output.ShortUrlRequest;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;

/**
 * 微信服务接口
 * party
 * Created by wei.li
 * on 2016/9/24 0024.
 */
@Service
public class WechatBizService {

    //小程序编号
    @Value("#{wechat['wechat.xcx.appid']}")
    private String xcxappid;

    //小程序密钥
    @Value("#{wechat['wechat.xcx.secret']}")
    private String xcxsecret;

    @Value("#{wechat_platform['wechat.platform.appId']}")
    private String componentAppid;

    // 运动打卡小程序appid
    @Value("#{wechat['wechat.xcx_sign.appid']}")
    private String signXcxAppId;

    // 运动打卡小程序secret
    @Value("#{wechat['wechat.xcx_sign.secret']}")
    private String signXcxSecret;

    // 是否需要刷新小程序token
    @Value("#{wechat['wechat.xcx.refreshToken']}")
    private String refreshToken;

    /**
     * 相册小程序appid
     */
    @Value("#{wechat['wechat.xcx_photo.appid']}")
    private String photoXcxAppId;

    /**
     * 相册小程序secret
     */
    @Value("#{wechat['wechat.xcx_photo.secret']}")
    private String photoXcxSecret;

    /**
     * 相册小程序appid
     */
    @Value("#{wechat['wechat.xcx_score.appid']}")
    private String scoreXcxAppId;

    /**
     * 相册小程序secret
     */
    @Value("#{wechat['wechat.xcx_score.secret']}")
    private String scoreXcxSecret;


    /**
     * 积分小程序appid
     */
    @Value("#{wechat['wechat.xcx_integral.appid']}")
    private String integralXcxAppId;

    /**
     * 积分小程序secret
     */
    @Value("#{wechat['wechat.xcx_integral.secret']}")
    private String integralXcxSecret;

    protected static Logger logger = LoggerFactory.getLogger(WechatBizService.class);

    //appid 请求参数
    public static final String APPID = "APPID";

    //重定向路径请求参数
    public static final String REDIRECT_URI = "REDIRECT_URI";

    //应用授权作用域
    public static final String SCOPE = "SCOPE";

    //重定向后会带上state参数，开发者可以填写a-zA-Z0-9的参数值，最多128字节
    public static final String STATE = "STATE";

    //微信公众平台秘钥
    public static final String SECRET = "SECRET";

    //微信授权会话码
    public static final String CODE = "CODE";

    //微信接口凭证
    public static final String ACCESS_TOKEN = "ACCESS_TOKEN";

    //微信公众号编号
    public static final String OPENID = "OPENID";

    private static final String REDIS_XCX_FORMID_LIST_KEY = "xcxFormIdListKey";

    @Autowired
    StringJedis stringJedis;

    @Autowired
    private IWechatAccountService wechatAccountService;

    @Autowired
    private IMemberMerchantService memberMerchantService;

    @Autowired
    private IWechatMerchantService wechatMerchantService;

    @Autowired
    private IMemberExternalAppService memberExternalAppService;

    @Autowired
    private IWechatOpenMemberService wechatOpenMemberService;

    @Autowired
    private IWechatMerchantsService wechatMerchantsService;

    @Autowired
    private IWechatPlatformService wechatPlatformService;

    @Autowired
    private IWechatOpenPlatformService wechatOpenPlatformService;

    @Autowired
    private WechatTokenBizService wechatTokenBizService;

    @Autowired
    private IWechatSubscribeService wechatSubscribeService;

    /**
     * 生成微信授权url
     * @param redirectUri 重定向url
     * @return 授权url
     * @throws UnsupportedEncodingException
     */
    public String getOathorizeUrl(String redirectUri) throws UnsupportedEncodingException {
        redirectUri = URLEncoder.encode(redirectUri, Charsets.UTF_8.name());
        String url = WechatConstant.OATHORIZE_URL.replace(APPID, wechatOpenMemberService.getSystem().getAuthorizerAppid())
                .replace(REDIRECT_URI, redirectUri)
                .replace(SCOPE, WechatConstant.SCOPE_USERINFO);

        return url;
    }

    /**
     * 生成微信授权url（普通授权）
     * @param redirectUri 重定向url
     * @param memberMerchant
     * @return 授权url
     * @throws UnsupportedEncodingException
     */
    public String getBaseOathorizeUrl(String redirectUri, MemberMerchant memberMerchant) throws UnsupportedEncodingException {
        redirectUri = URLEncoder.encode(redirectUri, Charsets.UTF_8.name());
        String url = "";
        // 获取绑定商户
        if (memberMerchant != null && memberMerchant.getOpenStatus().equals(YesNoStatus.YES.getCode())) {
        	String appId = memberMerchant.getOfficialAccountId();
        	url = WechatConstant.OATHORIZE_URL.replace(APPID, appId)
                    .replace(REDIRECT_URI, redirectUri)
                    .replace(SCOPE, WechatConstant.SCOPE_USERINFO);
		} else {
			url = WechatConstant.OATHORIZE_URL.replace(APPID, wechatOpenMemberService.getSystem().getAuthorizerAppid())
					.replace(REDIRECT_URI, redirectUri)
					.replace(SCOPE, WechatConstant.SCOPE_USERINFO);
		}
        return url;
    }


    /**
     * 生成微信授权url（普通授权）
     * @param redirectUri 重定向url
     * @param member
     * @return 授权url
     * @throws UnsupportedEncodingException
     */
    public String getBaseOathorizeUrl(String redirectUri, MemberGroup member) throws UnsupportedEncodingException {
        redirectUri = URLEncoder.encode(redirectUri, Charsets.UTF_8.name());
        String url = "";
        // 获取绑定商户
        if (member != null && member.getOpenStatus().equals(YesNoStatus.YES.getCode())) {
            MemberExternalApp memberExternalApp
                    = memberExternalAppService.findByMemberIdAndDeployType(member.getId(),
                    member.getDeployType());
            WechatOpenMember wechatOpenMember = wechatOpenMemberService.get(memberExternalApp.getExternalAccountId());
            String appId = wechatOpenMember.getAuthorizerAppid();
            url = WechatConstant.OATHORIZE_URL.replace(APPID, appId)
                    .replace(REDIRECT_URI, redirectUri)
                    .replace(SCOPE, WechatConstant.SCOPE_USERINFO);
        } else {
            url = WechatConstant.OATHORIZE_URL.replace(APPID, wechatOpenMemberService.getSystem().getAuthorizerAppid())
                    .replace(REDIRECT_URI, redirectUri)
                    .replace(SCOPE, WechatConstant.SCOPE_USERINFO);
        }
        return url;
    }

    public String getSnsapiBaseCodeUrl(String redirectUri, String appId, Integer deployType,
                                       String wechatOpenMemberId, String wechatMerchantId) throws Exception {
        String state = wechatOpenMemberId + "AAB0BAA" + wechatMerchantId + "AAB0BAA" + deployType;
        //redirectUri = redirectUri.replace("http:", "https:");
        redirectUri = URLEncoder.encode(redirectUri, Charsets.UTF_8.name());
        String url = WechatConstant.OATHORIZE_URL.replace(APPID, appId)
                .replace(REDIRECT_URI, redirectUri)
                .replace(SCOPE, WechatConstant.SCOPE_BASE)
                .replace(STATE, state);
        return url;
    }

    public String getAuthorizationSnsapiBaseCodeUrl(String redirectUri, String appId, Integer deployType,
                                       String wechatOpenMemberId, String wechatMerchantId) throws Exception {
        String state = wechatOpenMemberId + "AAB0BAA" + wechatMerchantId + "AAB0BAA" + deployType;
        //redirectUri = redirectUri.replace("http:", "https:");
        redirectUri = URLEncoder.encode(redirectUri, Charsets.UTF_8.name());
        String url = WechatConstant.OAUTH2_URL
                .replace("COMPONENT_APPID", componentAppid)
                .replace(APPID, appId)
                .replace(REDIRECT_URI, redirectUri)
                .replace("snsapi_userinfo", WechatConstant.SCOPE_BASE)
                .replace(STATE, state);
        return url;
    }

    public AccessTokenResponseWithError getSnsapiBaseOpenId(String appId, String code) {
        WechatOpenMember wechatOpenMember = wechatOpenMemberService.findByAppidAndDeployType(appId, 1);
        String secret = wechatOpenMember.getSecret();
        String url = WechatConstant.ACCESS_TOKEN_URL.replace(APPID, appId)
                .replace(SECRET, secret)
                .replace(CODE, code);
        logger.info("获取微信网页授权交互凭证请求报文{}", url);
        JSONObject response = WechatUtils.httpRequest(url, WechatUtils.GET, null);

        logger.info("获取微信网页收取交互凭证响应报文{}", response);
        if (null == response){
            return null;
        }
        return JSONObject.toJavaObject(response, AccessTokenResponseWithError.class);
    }

    public AccessTokenResponseWithError getSnsapiBaseOpenIdInAuthorization(String appId, String code) {
        AccessTokenResponseWithError r = new AccessTokenResponseWithError();
        WechatOpenPlatform wechatOpenPlatform = wechatOpenPlatformService.get();
        Oauth2AccessTokenResponse response = wechatPlatformService.getOauth2AccessToken(appId, code, componentAppid, wechatOpenPlatform.getComponentAccessToken());
        if (null != response) {
            r.setAccessToken(response.getAccessToken());
            r.setExpiresIn(response.getExpiresIn());
            r.setOpenid(response.getOpenid());
            r.setRefreshToken(response.getRefreshToken());
            r.setScope(response.getScope());
        }
        return r;
    }

    /**
     * 获取交互凭证
     * @param code 授权code
     * @param memberMerchant 业务发布者关联的商户信息
     * @return 交互数据
     */
    public AccessTokenResponse acccessToken(String code, MemberMerchant memberMerchant){
        String url = "";
        // 获取绑定商户
        if (memberMerchant != null && memberMerchant.getOpenStatus().equals(YesNoStatus.YES.getCode())) {
			String appId = memberMerchant.getOfficialAccountId();
			String appSecret = memberMerchant.getOfficialAccountSecret();
			url = WechatConstant.ACCESS_TOKEN_URL.replace(APPID, appId)
	                .replace(SECRET, appSecret)
	                .replace(CODE, code);
		} else {
            WechatOpenMember wechatOpenMember = wechatOpenMemberService.getSystem();
			url = WechatConstant.ACCESS_TOKEN_URL.replace(APPID, wechatOpenMember.getAuthorizerAppid())
	                .replace(SECRET, wechatOpenMember.getSecret())
	                .replace(CODE, code);
		}

        logger.info("获取微信网页授权交互凭证请求报文{}", url);
        JSONObject response = WechatUtils.httpRequest(url, WechatUtils.GET, null);

        logger.info("获取微信网页收取交互凭证响应报文{}", response);
        if (null == response){
            return null;
        }

        return JSONObject.toJavaObject(response, AccessTokenResponse.class);
    }


    /**
     * 获取交互凭证
     * @param code 授权code
     * @param member 业务发布者关联的商户信息
     * @return 交互数据
     */
    public AccessTokenResponse acccessToken(String code, MemberGroup member){
        String url = "";
        // 获取绑定商户
        if (member != null && member.getOpenStatus().equals(YesNoStatus.YES.getCode())) {
            MemberExternalApp memberExternalApp
                    = memberExternalAppService.findByMemberIdAndDeployType(member.getId(),
                    member.getDeployType());
            WechatOpenMember wechatOpenMember = wechatOpenMemberService.get(memberExternalApp.getExternalAccountId());
            String appId = wechatOpenMember.getAuthorizerAppid();
            String appSecret = wechatOpenMember.getSecret();
            url = WechatConstant.ACCESS_TOKEN_URL.replace(APPID, appId)
                    .replace(SECRET, appSecret)
                    .replace(CODE, code);
        } else {
            WechatOpenMember wechatOpenMember = wechatOpenMemberService.getSystem();
            url = WechatConstant.ACCESS_TOKEN_URL.replace(APPID, wechatOpenMember.getAuthorizerAppid())
                    .replace(SECRET, wechatOpenMember.getSecret())
                    .replace(CODE, code);
        }

        logger.info("获取微信网页授权交互凭证请求报文{}", url);
        JSONObject response = WechatUtils.httpRequest(url, WechatUtils.GET, null);

        logger.info("获取微信网页收取交互凭证响应报文{}", response);
        if (null == response){
            return null;
        }

        return JSONObject.toJavaObject(response, AccessTokenResponse.class);
    }

    /**
     * 获取小程序交互凭证
     *
     * @param code   授权code
     * @param appId  appid
     * @return
     */
    public JSONObject getXcxOpenId(String code, String appId) {
        String url = WechatConstant.XCX_ACCESS_TOKEN_URL;
        if (StringUtils.isNotEmpty(appId)) {
            WechatOpenMember openMember = wechatOpenMemberService.findByAppid(appId);
            url = url.replace(APPID, appId)
                    .replace(SECRET, openMember.getSecret())
                    .replace(CODE, code);
        } else {
            url = url.replace(APPID, xcxappid)
                    .replace(SECRET, xcxsecret)
                    .replace(CODE, code);
        }

        logger.info("获取小程序授权交互凭证请求报文{}", url);
        JSONObject response = WechatUtils.httpRequest(url, WechatUtils.GET, null);

        logger.info("获取小程序收取交互凭证响应报文{}", response);
        if (null == response) {
            return null;
        }

        return response;
    }


    /**
     * 获取微信用户信息
     * @param openid 用户编号
     * @return 交互数据
     */
    public UserInfoResponse userInfo(String openid, String accessToken) throws Exception {
        String url = WechatConstant.USERINFO_URL.replace(ACCESS_TOKEN, accessToken)
                .replace(OPENID, openid);

        logger.info("获取微信用户信息请求报文{}", url);
        JSONObject response = WechatUtils.httpRequest(url, WechatUtils.GET, null);

        logger.info("获取微信用户信息响应报文{}", response);
        if (null == response){
            throw new Exception("获取微信用户信息异常");
        }
        return JSONObject.toJavaObject(response, UserInfoResponse.class);
    }


    /**
     * 获取用户基本信息
     * @param openid 用户
     * @param accessToken 交互令牌
     */
    public InfoResponse info(String openid, String accessToken){
        String url = WechatConstant.USER_INFO_URL.replace(ACCESS_TOKEN, accessToken)
                .replace(OPENID, openid);

        logger.info("获取用户基本信息请求参数{}", url);
        JSONObject response = WechatUtils.httpRequest(url, WechatUtils.GET, null);
        logger.info("获取用户基本信息响应参数{}", response.toJSONString());

        if (null != response.get("errcode") && !"0".equals(response.get("errcode").toString())) {
            logger.error("获取用户基本信息响应参数异常：openId：{}, {}", openid, response.toJSONString());
        }

        return JSONObject.toJavaObject(response, InfoResponse.class);
    }


    /**
     * 获取微信 jsapi ticket
     * @param accessToken 接口交互令牌
     * @return 交互数据
     */
    public GetTicketResponse getTicket(String accessToken) throws Exception {
        String url = WechatConstant.GET_TICKET_URL.replace(ACCESS_TOKEN, accessToken);
        logger.info("获取 js api ticket 请求报文{}", url);
        JSONObject response = WechatUtils.httpRequest(url, WechatUtils.GET, null);

        logger.info("获取微信 js api ticket 响应报文{}", response);
        GetTicketResponse ticketResponse = JSONObject.toJavaObject(response, GetTicketResponse.class);
        if (StringUtils.isEmpty(ticketResponse.getTicket())) {
            throw new Exception("刷新ticket异常：" + JSONObject.toJSONString(response));
        }
        return ticketResponse;
    }


    /**
     * 微信长连接转短连接
     * @param longUrl 长连接
     * @param accessToken 交互令牌
     * @return 返回连接
     */
    public String longToShort(String longUrl, String accessToken){
        if (StringUtils.isEmpty(accessToken)) {
            return null;
        }
        String url = WechatConstant.LONG_TO_SHORT_URL.replace(ACCESS_TOKEN, accessToken);
        ShortUrlRequest shorturlRequest = new ShortUrlRequest( longUrl);
        logger.info("微信长连接转短链接请求报文{}", shorturlRequest.toString());
        JSONObject jsonObject = WechatUtils.httpRequest(url, WechatUtils.POST, JSONObject.toJSONString(shorturlRequest));
        logger.info("微信长连接转短连接响应报文{}", jsonObject);

        ShortUrlResponse shortUrlResponse = JSONObject.toJavaObject(jsonObject, ShortUrlResponse.class);
        return  shortUrlResponse.getShortUrl();
    }

    /**
     * 是否关注
     * @param memberId 第三方商户编号
     * @param openid 用户编号
     * @return 是否订阅（true/false）
     */
    public boolean isSubscribe(String memberId, String openid) {
        if (StringUtils.isEmpty(openid)) {
            return false;
        }
        String appid = null;
        String accessToken = null;

        WechatOpenMember wechatOpenMember = wechatOpenMemberService.findByMemberId(memberId);
        if (null != wechatOpenMember) {
            appid = wechatOpenMember.getAuthorizerAppid();
            accessToken = wechatOpenMember.getAuthorizerAccessToken();
        }
//        if (StringUtils.isNotEmpty(appid)) {
//            WechatSubscribe wechatSubscribe = wechatSubscribeService.get(appid, openid);
//            if (null != wechatSubscribe) {
//                if (wechatSubscribe.getStatus().equals(WechatConstant.EVENT_TYPE_SUBSCRIBE)) {
//                    return true;
//                } else {
//                    return false;
//                }
//            }
//        }
        if (StringUtils.isEmpty(accessToken)) {
            wechatOpenMember = wechatOpenMemberService.getSystem();
            accessToken = wechatOpenMember.getAuthorizerAccessToken();
        }

        InfoResponse infoResponse = this.info(openid, accessToken);
        if (null != infoResponse.getSubscribe()) {
            if ("1".equals(infoResponse.getSubscribe())) {
                wechatSubscribeService.subscribe(appid, openid);
                return true;
            } else if ("0".equals(infoResponse.getSubscribe())) {
                wechatSubscribeService.unSubscribe(appid, openid);
                return false;
            }
        }
        return false;
    }

    /**
     * 长连接转短连接
     *
     * @param longUrl
     * @return
     */
    public String longToShort2(String longUrl, String publisher) {
        String token = null;
        if (StringUtils.isNotEmpty(publisher)) {
            // 如果发布者绑定了自己的商户，就使用自己的token，否则就使用系统的token
            WechatOpenMember wechatOpenMember = wechatOpenMemberService.findByMemberId(publisher);
            if (null != wechatOpenMember) {
                token = wechatOpenMember.getAuthorizerAccessToken();
            }
            if (StringUtils.isEmpty(token)) {
                wechatOpenMember = wechatOpenMemberService.getSystem();
                token = wechatOpenMember.getAuthorizerAccessToken();
            }
        } else {
            WechatOpenMember wechatOpenMember = wechatOpenMemberService.getSystem();
            token = wechatOpenMember.getAuthorizerAccessToken();
        }
        return longToShort(longUrl, token);
    }

    /**
     * 初始化运动打卡小程序微信账户
     */
    public void initSignXcxWechatAccount() {
        try {
            this.initXcxAccount(signXcxAppId, signXcxSecret, "打卡画押", Constant.WECHAT_ACCOUNT_TYPE_SYSTEM_XCX_SIGN);
        } catch (Exception e) {
            logger.error("初始化小程序accessToken异常", e);
        }
    }

    /**
     * 小程序token是否需要刷新
     *
     * @param appId 小程序APPID
     * @return
     */
    public boolean refreshToken(String appId) {
        if (StringUtils.isNotEmpty(appId)) {
            if (appId.equals(signXcxAppId) || appId.equals(xcxappid) || appId.equals(photoXcxAppId) || appId.equals(integralXcxAppId)) {
                if (refreshToken.equals("true")) {
                    return true;
                } else {
                    return false;
                }
            } else {
                return true;
            }
        }
        return true;
    }

    /**
     * 初始化相册小程序微信账号
     */
    public void initPhotoXcxAccount() {
        try {
            this.initXcxAccount(photoXcxAppId, photoXcxSecret, "行者相册", Constant.WECHAT_ACCOUNT_TYPE_SYSTEM_XCX_PHOTO);
        } catch (Exception e) {
            logger.error("初始化小程序accessToken异常", e);
        }
    }

    /**
     * 初始化争分小程序微信账号
     */
    public void initScoreXcxAccount() {
        try {
            this.initXcxAccount(scoreXcxAppId, scoreXcxSecret, "争分", Constant.WECHAT_ACCOUNT_TYPE_SYSTEM_XCX_SCORE);
        } catch (Exception e) {
            logger.error("初始化小程序accessToken异常", e);
        }
    }
    /**
     * 初始化小程序账号
     *
     * @param appId
     * @param appSecret
     * @param appName
     * @param xcxType
     * @throws Exception
     */
    public void initXcxAccount(String appId, String appSecret, String appName, String xcxType) throws Exception {
        String token = wechatTokenBizService.getToken(appId, appSecret);
        WechatOpenMember openMember = wechatOpenMemberService.findByAppid(appId);
        if (openMember == null) {
            openMember = new WechatOpenMember();
            openMember.setNickName(appName);
            openMember.setAuthorizerAppid(appId);
            openMember.setSecret(appSecret);
            openMember.setType(xcxType);
            openMember.setDeployType(Constant.DEPLOY_TYPE_FILL);
            openMember.setAuthorizerAccessToken(token);
            wechatOpenMemberService.insert(openMember);
        } else {
            openMember.setAuthorizerAccessToken(token);
            wechatOpenMemberService.update(openMember);
        }
    }
    /**
     * 初始化行知公社小程序微信账号
     */
    public void initIntegralXcxAccount() {
        try {
            this.initXcxAccount(integralXcxAppId, integralXcxSecret, "积分", Constant.WECHAT_ACCOUNT_TYPE_SYSTEM_XCX_INTEGRAL);
        } catch (Exception e) {
            logger.error("初始化小程序accessToken异常", e);
        }
    }
}
